#include "rep.hpp"
#include "gc.h"

#include <ext/hash_map>

namespace rep{

  Slot* FrameHelper::alloc(FrameType *typ){
    Slot* frame = new (GC) Slot[typ->numSlots];
    frame->sz = typ->numSlots;
    frame->ftype = typ;
    return frame;
  } 

  size_t FrameHelper::memSize(Slot* in){
    assert(in->tag == Slot::FRAME);
    return sizeof(Slot) * in->obj->sz;
  }

  Type* FrameHelper::type(Slot* in){
    assert(in->tag == Slot::FRAME);
    return in->obj->ftype;
  }

  int FrameHelper::hashCode(Slot* in){
    static hash<int> h; 
    assert(in->tag == Slot::FRAME);
    return h((int)in->obj);
  }

  void FrameHelper::assign(Slot* to, Slot* rvalue){
    to->tag = Slot::FRAME;
    to->obj = rvalue;
  }

  Slot* FrameHelper::immDirectLookup(Slot* in, int offst){
    return in+offst;
  }

  Slot* FrameHelper::directLookup(Slot* in, int offst){
    assert(in->tag == Slot::FRAME);
    return in->obj+offst;
  }

  Slot* FrameHelper::immAncestralLookup(Slot* in, int generations, int offst){
    Slot* cur = in;
    for(int i = 0; i<generations; i++){
      if(!cur){
        throw "Error in lexical scope depth";
      }
      cur = FrameHelper::immParent(cur);
    }
    return cur+offst;
  }

  Slot* FrameHelper::ancestralLookup(Slot* in, int generations, int offst){
    assert(in->tag == Slot::FRAME);
    return immAncestralLookup(in->obj, generations, offst);
  }


  Slot* FrameHelper::parent(Slot* in){
    assert(in->tag == Slot::FRAME);
    return immParent(in->obj);
  }

  Slot* FrameHelper::immParent(Slot* in){
    if(in->ftype->lexicalEnvironment){
      return in->ftype->lexicalEnvironment;
    }
    return NULL;
  }

  int FrameHelper::size(Slot* in){
    assert(in->tag == Slot::FRAME);
    return in->obj->sz;
  }

  string* FrameHelper::toString(Slot* in){
    return NULL;
  }

  /**
   * Look in the standard place for the exception continuation.
   */
  Continuation* FrameHelper::exception(Slot* in){
    return FrameHelper::immException(in->obj);
  }

  Continuation* FrameHelper::immException(Slot* in){
    Slot* ans = FrameHelper::immDirectLookup(in, Slot::EXCEPT);
    if(ans && ans->tag == Slot::CONTINUE){
      return ans->cont;
    }
    return NULL;
  }

  /**
   * Look in the standard place for the return continuation.
   */
  Continuation* FrameHelper::ret(Slot* in){
    Slot* ans = immDirectLookup(in, Slot::RETURN);
    if(ans && ans->tag == Slot::CONTINUE)
      return ans->cont;
    return NULL;
  }

  /**
   * Look in the standard place for the exception continuation.
   */
  Continuation* FrameHelper::except(Slot* in){
    Slot* ans = immDirectLookup(in, Slot::EXCEPT);
    if(ans && ans->tag == Slot::CONTINUE)
      return ans->cont;
    return NULL;
  }

  /**
   * Loook in the standard place for the yield continuation.
   */
  Continuation* FrameHelper::yield(Slot* in){
    Slot* ans = immDirectLookup(in, Slot::YIELD);
    if(ans && ans->tag == Slot::CONTINUE)
      return ans->cont;
    return NULL;
  }


  /**
   * Loook in the standard place for the if done continuation.
   */
  Continuation* FrameHelper::ifdone(Slot* in){
    Slot* ans = immDirectLookup(in, Slot::IFDONE);
    if(ans && ans->tag == Slot::CONTINUE)
      return ans->cont;
    return NULL;
  }

  /**
   * Loook in the standard place for the break continuation.
   */
  Continuation* FrameHelper::br(Slot* in){
    Slot* ans = immDirectLookup(in, Slot::BREAK);
    if(ans && ans->tag == Slot::CONTINUE)
      return ans->cont;
    return NULL;
  }


  /**
   * Loook in the standard place for the continue (for a loop) continuation.
   */
  Continuation* FrameHelper::cont(Slot* in){
    Slot* ans = immDirectLookup(in, Slot::CONT);
    if(ans && ans->tag == Slot::CONTINUE)
      return ans->cont;
    return NULL;
  }



};
